﻿#region Apache 2.0 License header

//   Copyright 2012 Lesley van Zijl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License. 

#endregion

using System;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Reflection.Emit;

namespace FavourObjects.ForwardBuilders
{
    internal abstract class ForwardPropertyBuilderBase<TTargetClass>
        where TTargetClass : class
    {
        protected const MethodAttributes PropertyMethodAttributes = MethodAttributes.Public |
                                                                    MethodAttributes.SpecialName |
                                                                    MethodAttributes.HideBySig |
                                                                    MethodAttributes.Virtual;

        protected const BindingFlags BindingFlagsForAllMembers = (BindingFlags.Public |
                                                                  BindingFlags.NonPublic |
                                                                  BindingFlags.Instance |
                                                                  BindingFlags.Static);

        protected ForwardPropertyBuilderBase(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder,
                                             FieldInfo innerObjectField)
        {
            TypeBuilder = typeBuilder;
            PropertyBuilder = propertyBuilder;
            InnerObjectFieldInfo = innerObjectField;

            MethodRegistry = MemberInfoCache.ActiveCache;
        }

        protected TypeBuilder TypeBuilder { get; private set; }
        protected PropertyBuilder PropertyBuilder { get; private set; }
        protected FieldInfo InnerObjectFieldInfo { get; private set; }

        protected MemberInfoCache MethodRegistry { get; private set; }

        protected void EmitGetTargetClassType(ILGenerator ilGenerator, int localTargetTypeField)
        {
            Contract.Requires(ilGenerator != null);

            ilGenerator.Emit(OpCodes.Ldtoken, typeof (TTargetClass));

            MethodInfo getTypeFromHandleMethod = MethodRegistry.GetMethod(typeof (Type), "GetTypeFromHandle",
                                                                          typeof (RuntimeTypeHandle));

            ilGenerator.Emit(OpCodes.Call, getTypeFromHandleMethod);

            ilGenerator.Emit(OpCodes.Stloc_S, localTargetTypeField);
        }
    }
}